package com.zhuangfei.timetable.view;

import com.zhuangfei.timetable.model.Schedule;
import com.zhuangfei.timetable.model.ScheduleEnable;
import com.zhuangfei.timetable.model.ScheduleSupport;
import com.zhuangfei.timetable.utils.AttrUtils;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

import java.util.ArrayList;
import java.util.List;

/**
 * 周次选择栏的每项自定义View,表示某周的有课情况.
 * 使用周一至周五、第1-10节的数据进行绘制,绘制的结果是一个5x5的点阵：
 * 5列分别表示周一至周五
 * 5行分别表示1-2节、3-4节、5-6节、7-8节、9-10节的有课情况
 * 有课的地方用亮色的圆点，没课的地方用暗色的圆点
 */
public class PerWeekView extends Component {
    private static final String TAG = "PerWeekView";
    HiLogLabel hiLogLabel = new HiLogLabel(3, 3, TAG);

    private final Context context;

    /**
     * 控件宽度
     */
    private int width;

    /**
     * 圆点半径
     */
    private int radius;

    /**
     * 亮色画笔
     */
    private Paint lightPaint;

    /**
     * 暗色画笔
     */
    private Paint grayPaint;

    /**
     * 亮色
     */
    private int lightColor;

    /**
     * 暗色
     */
    private int grayColor;

    /**
     * 亮色
     */
    private Color lightColors;

    /**
     * 暗色
     */
    private Color grayColors;

    /**
     * 数据源
     */
    private List<Schedule> dataSource;

    /**
     * 获取亮色的画笔
     *
     * @return Paint
     */
    public Paint getLightPaint() {
        return lightPaint;
    }

    /**
     * 获取暗色的画笔
     *
     * @return Paint
     */
    public Paint getGrayPaint() {
        return grayPaint;
    }

    /**
     * 设置亮色
     *
     * @param lightColor 亮色
     * @return PerWeekView
     */
    public PerWeekView setLightColor(int lightColor) {
        this.lightColor = lightColor;
        invalidate();
        return this;
    }

    /**
     * 设置暗色
     *
     * @param grayColor
     * @return PerWeekView
     */
    public PerWeekView setGrayColor(int grayColor) {
        this.grayColor = grayColor;
        invalidate();
        return this;
    }

    /**
     * 获取数据源
     *
     * @return List
     */
    public List<Schedule> getDataSource() {
        if (dataSource == null) {
            dataSource = new ArrayList<>();
        }
        return dataSource;
    }

    /**
     * 设置数据源
     *
     * @param list
     * @param curWeek
     * @return PerWeekView
     */
    public PerWeekView setSource(List<? extends ScheduleEnable> list, int curWeek) {
        if (list == null) {
            return this;
        }
        setData(ScheduleSupport.transform(list), curWeek);
        return this;
    }

    /**
     * 设置数据源
     *
     * @param list
     * @param curWeek
     * @return PerWeekView
     */
    public PerWeekView setData(List<Schedule> list, int curWeek) {
        if (list == null) {
            return this;
        }
        getDataSource().clear();
        for (int i = 0; i < list.size(); i++) {
            Schedule schedule = list.get(i);
            if (ScheduleSupport.isThisWeek(schedule, curWeek) && schedule.getStart() <= 10 && schedule.getDay() <= 5) {
                getDataSource().add(schedule);
            }
        }
        invalidate();
        return this;
    }

    /**
     * 设置半径Px
     *
     * @param radiusPx 半径
     * @return PerWeekView
     */
    public PerWeekView setRadiusInPx(int radiusPx) {
        this.radius = radius;
        return this;
    }

    /**
     * 设置半径Dp
     *
     * @param radiusDp 半径
     * @return PerWeekView
     */
    public PerWeekView setRadiusInDp(int radiusDp) {
        setRadiusInPx(radiusDp);
        return this;
    }

    public PerWeekView(Context context) {
        this(context, null);
    }

    public PerWeekView(Context context, AttrSet attrs) {
        super(context, attrs);
        this.context = context;
        initAttr(attrs);

        lightPaint = new Paint();
        lightPaint.setColor(new Color(lightColor));
        lightPaint.setAntiAlias(true);
        lightPaint.setStyle(Paint.Style.FILL_STYLE);

        grayPaint = new Paint();
        grayPaint.setColor(new Color(grayColor));
        grayPaint.setAntiAlias(true);
        grayPaint.setStyle(Paint.Style.FILL_STYLE);
    }

    private void initAttr(AttrSet attrs) {
        int defRadius = 2;
        width = getWidth();
        grayColors = AttrUtils.getColor(attrs, "gray_color", new Color(Color.rgb(207, 219, 219)));
        lightColors = AttrUtils.getColor(attrs, "light_color", new Color(Color.rgb(63, 202, 184)));

        radius = AttrUtils.getInt(attrs, "radius", defRadius);


        addDrawTask(new DrawTask() {
            @Override
            public void onDraw(Component component, Canvas canvas) {
                int mar = (width - 10 * radius) / 6;
                lightPaint.setColor(lightColors);
                grayPaint.setColor(grayColors);
                debug("" + mar);
                int[][] tmp = getArray();

                /**
                 * 绘制点
                 */
                for (int i = 0; i < 5; i++) {
                    for (int j = 0; j < 5; j++) {
                        if (tmp[i][j] == 0) {
                            drawPoint(canvas, mar + radius + (mar + 2 * radius) * j, mar + radius + (mar + 2 * radius) * i, radius, grayPaint);
                        } else {
                            drawPoint(canvas, mar + radius + (mar + 2 * radius) * j, mar + radius + (mar + 2 * radius) * i, radius, lightPaint);
                        }
                    }
                }
                invalidate();
            }
        });

        setLayoutRefreshedListener(new LayoutRefreshedListener() {
            @Override
            public void onRefreshed(Component component) {
                width = component.getWidth();
                invalidate();
            }
        });
    }

    /**
     * 根据此数据源分析出一个二维数组.
     *
     * @return int[][]
     */
    public int[][] getArray() {
        int[][] arr = new int[10][5];
        int[][] tmp = new int[5][5];

        // 初始化数组
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 5; j++) {
                arr[i][j] = 0;
            }
        }
        /**
         * 标记上课的位置
         * 遍历课程集合，将在某课程的上课区间的位置都标记上
         */
        int start;
        int end;
        for (int i = 0; i < getDataSource().size(); i++) {
            Schedule schedule = getDataSource().get(i);
            start = schedule.getStart();
            end = schedule.getStart() + schedule.getStep() - 1;
            if (end > 10) {
                end = 10;
            }
            /**
             * 标记区间的所有位置
             */
            for (int m = start; m <= end; m++) {
                arr[m - 1][schedule.getDay() - 1] = 1;
            }
        }
        /**
         * 合并分组标记
         * 用到了10小节的数据来标记
         * 10小节被分为了5组分别来表示5行的上课状态
         * 每个分组中只要有一个有课，那么该组对外的状态应该为有课
         */
        int t = 0;
        for (int i = 0; i < 10; i += 2) {
            for (int j = 0; j < 5; j++) {
                if (arr[i][j] == 0 && arr[i + 1][j] == 0) {
                    tmp[t][j] = 0;
                } else {
                    tmp[t][j] = 1;
                }
            }
            t++;
        }
        return tmp;
    }

    /**
     * 画点
     *
     * @param canvas
     * @param x      圆心x
     * @param y      圆心y
     * @param radius 半径
     * @param p      画笔
     */
    public void drawPoint(Canvas canvas, int x, int y, int radius, Paint p) {
        canvas.drawCircle(x, y, radius, p);
    }

    private void debug(String errorMsg) {
        HiLog.error(hiLogLabel, errorMsg);
    }
}
